package dl.bukkit.myststus.command;

import dl.bukkit.myststus.MyStatus;
import dl.bukkit.myststus.library.CommandSenderType;
import dl.bukkit.myststus.library.ats.GCommand;
import dl.bukkit.myststus.loader.Loader;
import dl.bukkit.myststus.logger.Logger;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;

public class CommandHandler implements Loader, TabExecutor {

    private final Map<String, ICommand> map = new HashMap<>();
    private final Map<ICommand, GCommand> gMap = new HashMap<>();

    private CommandHandler(MyStatus plugin) {
    }

    @Override
    public void onLoad() {
        register(ReloadCommand.class);
    }

    @Override
    public void staring() {
        Bukkit.getPluginCommand("MyStatus").setExecutor(this);
        Bukkit.getPluginCommand("MyStatus").setTabCompleter(this);
    }

    @Override
    public boolean onCommand(CommandSender sender, Command c, String l, String[] args) {
        if (args.length == 0) {
            for (Map.Entry<String, ICommand> entry : map.entrySet()) {
                if (isUse(sender, entry.getValue(), getType(sender))) {
                    sender.sendMessage("§7/ms " + entry.getKey() + " - §6" + entry.getValue().getHelp());
                }
            }
            return true;
        }
        ICommand iCommand = map.get(args[0].toLowerCase());
        if (iCommand == null) {
            Logger.prefixMessage(sender, "§c参数 §a", args[0], " §c不存在！");
            return true;
        }
        if (! isUse(sender, iCommand, getType(sender))) {
            Logger.prefixMessage(sender, "§c你需要拥有权限 §a", getPermission(iCommand));
            return true;
        }
        iCommand.onCommand(sender, args);
        return true;
    }


    @Override
    public List<String> onTabComplete(CommandSender sender, Command c, String l, String[] args) {
        CommandSenderType type = getType(sender);
        return args.length == 1 ? map.entrySet().stream().filter(entry ->
                isUse(sender,  entry.getValue(), type) && entry.getKey().startsWith(args[0]))
                .map(Map.Entry::getKey).collect(Collectors.toList()) :
                map.entrySet().stream().filter(entry -> entry.getKey().equalsIgnoreCase(args[0]))
                        .findFirst().filter(sub -> isUse(sender, sub.getValue(), type)).map(sub ->
                        sub.getValue().onTabComplete(sender, args)).orElse(null);
    }

    private CommandSenderType getType(CommandSender sender) {
        return sender instanceof Player ? CommandSenderType.PLAYER : CommandSenderType.CONSOLE;
    }


    public String getPermission(ICommand command) {
        return "ms." + gMap.get(command).cmd();
    }

    public boolean isUse(CommandSender sender, ICommand command, CommandSenderType type) {
        GCommand g = gMap.get(command);
        return sender.hasPermission(getPermission(command)) && g.type().equals(CommandSenderType.ALL) || g.type().equals(type);
    }

    private void register(Class<? extends ICommand> cls) {
        try {
            Constructor<? extends ICommand> constructor = cls.getDeclaredConstructor();
            constructor.setAccessible(true);
            GCommand annotation = cls.getAnnotation(GCommand.class);
            if (annotation == null) return;
            ICommand command = constructor.newInstance();
            map.put(annotation.cmd().toLowerCase(), command);
            gMap.put(command, annotation);
        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
